import sys
import time
from tkinter import *


class Timer:
    def __init__(self, wnd, ms, call):
        self.__wnd = wnd
        self.__ms = ms
        self.__call = call
        self.__running = False

    def start(self):
        if not self.__running:
            self.__wnd.after(0, self.__on_timer)
            self.__running = True

    def stop(self):
        if self.__running:
            self.__running = False

    def is_running(self):
        return self.__running

    def __on_timer(self):
        if self.__running:
            self.__call()
            self.__wnd.after(self.__ms, self.__on_timer)


class State:
    def __init__(self, owner, context):
        self.owner = owner
        self.context = context
        self.transitions = []

    def add_transition(self, t):
        self.transitions.append(t)

    def entry(self):
        for t in self.transitions:
            t.entry()
        if self.owner:
            self.owner.active = self

    def exit(self):
        if self.owner:
            self.owner.active = None

    def event_handling(self, e_type, event):
        for t in self.transitions:
            if t.event_handling(e_type, event):
                return True


class StateMachine(State):
    def __init__(self, owner, context):
        State.__init__(self, owner, context)
        self.active = None
        self.initial = None

    def entry(self):
        self.active = self.initial
        if self.active:
            self.active.entry()

    def event_handling(self, e_type, event):
        if self.active:
            return self.active.event_handling(e_type, event)

    def exit(self):
        pass


class Transition:
    def __init__(self, owner, context, s, t):
        self.owner = owner
        self.context = context
        self.source = s
        s.add_transition(self)
        self.target = t
        self.triggers = []
        self.__guard = None

    def add_trigger(self, t):
        self.triggers.append(t)

    def set_guard(self, g):
        self.__guard = g

    def entry(self):
        for t in self.triggers:
            t.entry()

    def effect(self):
        pass

    def event_handling(self, type_str, event):
        if self.__guard:
            if not self.__guard():
                return
        for t in self.triggers:
            if t.check():
                self.transition()
                break

    def transition(self):
        self.source.exit()
        self.target.entry()


class Trigger:
    def __init__(self, context):
        self.context = context

    def entry(self):
        pass

    def check(self):
        pass


class TimerTrigger(Trigger):
    def __init__(self, context, timer):
        Trigger.__init__(self, context)
        self.start = 0
        self.timer = timer

    def entry(self):
        self.start = time.time()

    def check(self):
        return (time.time() - self.start) > self.timer


class ValueTrigger(Trigger):
    def __init__(self, context, target, value):
        Trigger.__init__(self, context)
        self.value = value
        self.target = target

    def check(self):
        return self.value == eval(self.target)

class InitialState(State):
    def __init__(self, owner, context):
        State.__init__(self, owner, context)

    def event_handling(self, e_type, event):
        pass

    def entry(self):
        for t in self.transitions:
            t.transition()
            return True


class FinalState(State):
    def __init__(self, owner, context):
        State.__init__(self, owner, context)

    def event_handling(self, e_type, event):
        pass

    def entry(self):
        self.exit()


class TrafficLight:
    def __init__(self, parent):
        self.canvas = Canvas(parent, bg='#FFFFFF', relief=SUNKEN)
        self.canvas.config(width=300, height=100)
        self.canvas.pack()
        self.light = dict()
        self.light['red'] = \
        self.canvas.create_oval(10, 10, 90, 90, fill='#FF0000',
        disabledfill='#770000')
        self.light['yellow'] = \
        self.canvas.create_oval(110, 10, 190, 90, fill='#FFFF00',
        disabledfill='#777700')
        self.light['green'] = \
        self.canvas.create_oval(210, 10, 290, 90, fill='#00FF00',
        disabledfill='#007700')
        self.stop()

    def light_on(self, light):
        self.canvas.itemconfig(self.light[light], state=NORMAL)

    def light_off(self, light):
        self.canvas.itemconfig(self.light[light], state=DISABLED)

    def toggle(self, light):
        if self.canvas.itemcget(self.light[light], 'state') == NORMAL:
            self.light_off(light)
        else:
            self.light_on(light)

    def stop(self):
        self.light_off('red')
        self.light_off('yellow')
        self.light_off('green')
        self.run = False


class LightState(State):
    def __init__(self, owner, color, context, blink=False):
        State.__init__(self, owner, context)
        self.color = color
        self.blink = blink
        self.counter = 0

    def entry(self):
        State.entry(self)
        self.context.light_on(self.color)
        self.counter = 0

    def exit(self):
        State.exit(self)
        self.context.light_off(self.color)

    def event_handling(self, e_type, event):
        if self.blink:
            self.counter = self.counter + 1
            if self.counter >= 5:
                self.context.toggle(self.color)
                self.counter = 0
        State.event_handling(self, e_type, event)


class TrafficLightMachine(StateMachine):
    def __init__(self, context):
        StateMachine.__init__(self, None, context)
        #初始状态
        self.initial = InitialState(self, context)
        #红灯
        red = LightState(self, 'red', context)
        #绿灯
        green = LightState(self, 'green', context)
        #绿灯闪烁
        green5s= LightState(self, 'green', context, True)
        #黄灯1秒间隔闪烁
        yellow = LightState(self, 'yellow', context)
        #红灯1秒闪烁
        red5s = LightState(self, 'red', context, True)
        #终止状态
        final = FinalState(self, context)
        #初始状态为红灯，无条件迁移
        i2r = Transition(self, context, self.initial, red)
        #红灯→绿灯
        r2g = Transition(self, context, red, green)
        #5秒迁移
        r2g.add_trigger(TimerTrigger(context, 5))
        #绿灯→绿灯闪
        g2g5 = Transition(self, context, green, green5s)
        #5秒迁移
        g2g5.add_trigger(TimerTrigger(context, 3))
        #绿灯闪→黄灯
        g52y = Transition(self, context, green5s, yellow)
        #5秒迁移
        g52y.add_trigger(TimerTrigger(context, 2))
        #黄灯→红灯
        y2r = Transition(self, context, yellow, red)
        #3秒迁移
        y2r.add_trigger(TimerTrigger(context, 3))
        #红灯→红灯闪
        r2f = Transition(self, context, red, red5s)
        #监控context.run是否为False
        r2f.add_trigger(ValueTrigger(context, 'self.context.run',False))
        #红灯闪→终了
        r5s2f = Transition(self, context, red5s, final)
        #5秒迁移
        r5s2f.add_trigger(TimerTrigger(context, 5))

    def stop(self):
        self.context.run = False

    def entry(self):
        StateMachine.entry(self)
        self.context.run = True

    def exit(self):
        self.context.stop()


if __name__ == '__main__':
    root = Tk()
    tl = TrafficLight(root)
    tlm = TrafficLightMachine(tl)
    Button(root, text='Start', command=tlm.entry).pack(side=LEFT, fill=X, expand=1)
    Button(root, text='Stop', command=tlm.stop).pack(side=LEFT, fill=X, expand=1)
    t = Timer(root, 100, lambda:tlm.event_handling('on_timer', ''))
    t.start()
    root.mainloop()